/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

import QtQuick 2.0
import QtTest 1.0
import QtLocation 5.0
import QtPositioning 5.2

Item {
    Plugin { id: testPlugin; name: "qmlgeo.test.plugin"}
    Plugin { id: invalidPlugin; name: "invalid"}

    property variant coordinate1: QtPositioning.coordinate(51, 41)
    property variant coordinate2: QtPositioning.coordinate(52, 42)
    property variant coordinate3: QtPositioning.coordinate(53, 43)
    property variant emptyCoordinate: QtPositioning.coordinate()

    property variant boundingBox1: QtPositioning.rectangle(coordinate1, coordinate2)
    property variant boundingBox2: QtPositioning.rectangle(coordinate1, coordinate3)
    property variant boundingCircle1: QtPositioning.circle(coordinate1, 100)
    property variant boundingCircle2: QtPositioning.circle(coordinate2, 100)

    property variant emptyBox: QtPositioning.rectangle()

    GeocodeModel {id: emptyModel}

    Address {id: emptyAddress}
    SignalSpy {id: querySpy; target: emptyModel; signalName: "queryChanged"}
    SignalSpy {id: autoUpdateSpy; target: emptyModel; signalName: "autoUpdateChanged"}
    SignalSpy {id: pluginSpy; target: emptyModel ; signalName: "pluginChanged"}
    SignalSpy {id: boundsSpy; target: emptyModel; signalName: "boundsChanged"}
    SignalSpy {id: limitSpy; target: emptyModel; signalName: "limitChanged"}
    SignalSpy {id: offsetSpy; target: emptyModel; signalName: "offsetChanged"}

    TestCase {
        id: testCase1
        name: "Map GeocodeModel basic API"
        function test_model_defaults_and_setters() {
            // Query: address
            compare (querySpy.count, 0)
            emptyModel.query = address1
            compare (querySpy.count, 1)
            compare (emptyModel.query.street, address1.street)
            emptyModel.query = address1
            compare (querySpy.count, 1)
            compare (emptyModel.query.street, address1.street)
            // Query: coordinate
            emptyModel.query = coordinate1
            compare (querySpy.count, 2)
            compare (emptyModel.query.latitude, coordinate1.latitude)
            emptyModel.query = coordinate1
            compare (querySpy.count, 2)
            compare (emptyModel.query.latitude, coordinate1.latitude)
            // Query: string
            emptyModel.query = "Kuortane, Finland"
            compare (querySpy.count, 3)
            compare (emptyModel.query, "Kuortane, Finland")
            emptyModel.query = "Kuortane, Finland"
            compare (querySpy.count, 3)
            compare (emptyModel.query, "Kuortane, Finland")

            // limit and offset
            compare (limitSpy.count, 0)
            compare (offsetSpy.count, 0)
            compare(emptyModel.limit, -1)
            compare(emptyModel.offset, 0)
            emptyModel.limit = 2
            compare (limitSpy.count, 1)
            emptyModel.limit = 2
            compare (limitSpy.count, 1)
            emptyModel.offset = 10
            compare (offsetSpy.count, 1)
            emptyModel.offset = 10
            compare (offsetSpy.count, 1)

            // bounding box
            compare(boundsSpy.count, 0)
            emptyModel.bounds = boundingBox1
            compare(boundsSpy.count, 1)
            compare(emptyModel.bounds.topLeft.latitude, boundingBox1.topLeft.latitude)
            compare(emptyModel.bounds.bottomRight.longitude, boundingBox1.bottomRight.longitude)
            emptyModel.bounds = boundingBox1
            compare(boundsSpy.count, 1)
            compare(emptyModel.bounds.topLeft.latitude, boundingBox1.topLeft.latitude)
            compare(emptyModel.bounds.bottomRight.longitude, boundingBox1.bottomRight.longitude)
            emptyModel.bounds = boundingBox2
            compare(boundsSpy.count, 2)
            compare(emptyModel.bounds.topLeft.latitude, boundingBox2.topLeft.latitude)
            compare(emptyModel.bounds.bottomRight.longitude, boundingBox2.bottomRight.longitude)
            emptyModel.bounds = QtPositioning.rectangle();
            compare(boundsSpy.count, 3)


            // bounding circle
            boundsSpy.clear()
            emptyModel.bounds = boundingCircle1
            compare(boundsSpy.count, 1)
            compare(emptyModel.bounds.center.latitude, coordinate1.latitude)
            emptyModel.bounds = boundingCircle1
            compare(boundsSpy.count, 1)
            compare(emptyModel.bounds.center.latitude, coordinate1.latitude)
            emptyModel.bounds = boundingCircle2
            compare(boundsSpy.count, 2)
            compare(emptyModel.bounds.center.latitude, coordinate2.latitude)
            var dynamicCircle = QtPositioning.circle(QtPositioning.coordinate(8, 9));
            emptyModel.bounds = dynamicCircle
            compare(boundsSpy.count, 3)
            compare(emptyModel.bounds.center.latitude, dynamicCircle.center.latitude)

            // status
            compare (emptyModel.status, RouteModel.Null)

            // error
            compare (emptyModel.errorString, "")
            compare (emptyModel.error, GeocodeModel.NoError)

            // count
            compare( emptyModel.count, 0)

            // auto update
            compare (autoUpdateSpy.count, 0)
            compare (emptyModel.autoUpdate, false)
            emptyModel.autoUpdate = true
            compare (emptyModel.autoUpdate, true)
            compare (autoUpdateSpy.count, 1)
            emptyModel.autoUpdate = true
            compare (emptyModel.autoUpdate, true)
            compare (autoUpdateSpy.count, 1)

            // mustn't crash even we don't have plugin
            emptyModel.update()

            // Plugin
            compare(pluginSpy.count, 0)
            emptyModel.plugin = testPlugin
            compare(pluginSpy.count, 1)
            compare(emptyModel.plugin, testPlugin)
            emptyModel.plugin = testPlugin
            compare(pluginSpy.count, 1)
            emptyModel.plugin = invalidPlugin
            compare(pluginSpy.count, 2)
        }
        // Test that model acts gracefully when plugin is not set or is invalid
         // (does not support routing)
         GeocodeModel {id: invalidModel; plugin: invalidPlugin}
         SignalSpy {id: countInvalidSpy; target: invalidModel; signalName: "countChanged"}
         function test_invalid_plugin() {
             invalidModel.update()
             invalidModel.cancel()
             invalidModel.reset()
             invalidModel.update()
             invalidModel.get(-1)
             invalidModel.get(1)
         }

    }
    Address {id: address1; street: "wellknown street"; city: "expected city"; county: "2"}
    Address {id: errorAddress1; street: "error"; county: "2"} // street is the error reason

    property variant rcoordinate1: QtPositioning.coordinate(51, 2)
    property variant errorCoordinate1: QtPositioning.coordinate(73, 2)  // (latiude mod 70) is the error code
    property variant slackCoordinate1: QtPositioning.coordinate(60, 3)
    Address {id: slackAddress1; street: "Slacker st"; city: "Lazy town"; county: "4"}

    property variant automaticCoordinate1: QtPositioning.coordinate(60, 3)
    Address {id: automaticAddress1; street: "Auto st"; city: "Detroit"; county: "4"}

    Plugin {
        id: testPlugin;
        name: "qmlgeo.test.plugin"
        allowExperimental: true
        parameters: [
            // Parms to guide the test plugin
            PluginParameter { name: "supported"; value: true},
            PluginParameter { name: "finishRequestImmediately"; value: true},
            PluginParameter { name: "validateWellKnownValues"; value: true}
        ]
    }

    Plugin {
        id: immediatePlugin;
        name: "qmlgeo.test.plugin"
        allowExperimental: true
        parameters: [
            // Parms to guide the test plugin
            PluginParameter { name: "supported"; value: true},
            PluginParameter { name: "finishRequestImmediately"; value: true},
            PluginParameter { name: "validateWellKnownValues"; value: false}
        ]
    }

    Plugin {
        id: slackPlugin;
        allowExperimental: true
        name: "qmlgeo.test.plugin"
        parameters: [
            // Parms to guide the test plugin
            PluginParameter { name: "supported"; value: true},
            PluginParameter { name: "finishRequestImmediately"; value: false},
            PluginParameter { name: "validateWellKnownValues"; value: false}
        ]
    }

    Plugin {
        id: autoPlugin;
        allowExperimental: true
        name: "qmlgeo.test.plugin"
        parameters: [
            // Parms to guide the test plugin
            PluginParameter { name: "supported"; value: true},
            PluginParameter { name: "finishRequestImmediately"; value: false},
            PluginParameter { name: "validateWellKnownValues"; value: false}
        ]
    }

    GeocodeModel {id: testModel; plugin: testPlugin}
    SignalSpy {id: locationsSpy; target: testModel; signalName: "locationsChanged"}
    SignalSpy {id: countSpy; target: testModel; signalName: "countChanged"}
    SignalSpy {id: testQuerySpy; target: testModel; signalName: "queryChanged"}
    SignalSpy {id: testStatusSpy; target: testModel; signalName: "statusChanged"}

    GeocodeModel {id: slackModel; plugin: slackPlugin; }
    SignalSpy {id: locationsSlackSpy; target: slackModel; signalName: "locationsChanged"}
    SignalSpy {id: countSlackSpy; target: slackModel; signalName: "countChanged"}
    SignalSpy {id: querySlackSpy; target: slackModel; signalName: "queryChanged"}
    SignalSpy {id: errorStringSlackSpy; target: slackModel; signalName: "errorStringChanged"}
    SignalSpy {id: errorSlackSpy; target: slackModel; signalName: "errorChanged"}
    SignalSpy {id: pluginSlackSpy; target: slackModel; signalName: "pluginChanged"}

    GeocodeModel {id: immediateModel; plugin: immediatePlugin}
    SignalSpy {id: locationsImmediateSpy; target: immediateModel; signalName: "locationsChanged"}
    SignalSpy {id: countImmediateSpy; target: immediateModel; signalName: "countChanged"}
    SignalSpy {id: queryImmediateSpy; target: immediateModel; signalName: "queryChanged"}
    SignalSpy {id: statusImmediateSpy; target: immediateModel; signalName: "statusChanged"}
    SignalSpy {id: errorStringImmediateSpy; target: immediateModel; signalName: "errorStringChanged"}
    SignalSpy {id: errorImmediateSpy; target: immediateModel; signalName: "errorChanged"}

    GeocodeModel {id: automaticModel; plugin: autoPlugin; query: automaticAddress1; autoUpdate: true}
    SignalSpy {id: automaticLocationsSpy; target: automaticModel; signalName: "locationsChanged"}

    TestCase {
        name: "Map GeocodeModel basic (reverse) geocoding"
        function clear_slack_model() {
            slackModel.reset()
            locationsSlackSpy.clear()
            countSlackSpy.clear()
            querySlackSpy.clear()
            errorStringSlackSpy.clear()
            errorSlackSpy.clear()
            slackModel.limit = -1
            slackModel.offset = 0
        }
        function clear_immediate_model() {
            immediateModel.reset()
            locationsImmediateSpy.clear()
            countImmediateSpy.clear()
            queryImmediateSpy.clear()
            errorStringImmediateSpy.clear()
            errorImmediateSpy.clear()
            statusImmediateSpy.clear()
            immediateModel.limit = -1
            immediateModel.offset = 0
        }
        function test_reset() {
            clear_immediate_model();
            immediateModel.query = errorAddress1
            immediateModel.update()
            compare (immediateModel.errorString, errorAddress1.street)
            compare (immediateModel.error, RouteModel.CommunicationError)
            compare (immediateModel.count, 0)
            compare (statusImmediateSpy.count, 2)
            compare (immediateModel.status, GeocodeModel.Error)
            immediateModel.reset()
            compare (immediateModel.errorString, "")
            compare (immediateModel.error, GeocodeModel.NoError)
            compare (immediateModel.status, GeocodeModel.Null)
            // Check that ongoing req is aborted
            clear_slack_model()
            slackModel.query = slackAddress1
            slackAddress1.county = "5"
            slackModel.update()
            wait (100)
            compare (countSlackSpy.count, 0)
            compare (locationsSlackSpy.count, 0)
            compare (slackModel.count, 0)
            slackModel.reset()
            wait (200)
            compare (countSlackSpy.count, 0)
            compare (locationsSlackSpy.count, 0)
            compare (slackModel.count, 0)
            // Check that results are cleared
            slackModel.update()
            wait (300)
            compare (slackModel.count, 5) //  slackAddress1.county)
            slackModel.reset()
            compare (slackModel.count, 0)
            // Check that changing plugin resets any ongoing requests
            clear_slack_model()
            slackModel.query = slackAddress1
            slackAddress1.county = "7"
            compare (pluginSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare (countSlackSpy.count, 0)
            slackModel.plugin = invalidPlugin
            wait (200)
            compare (countSlackSpy.count, 0)
            compare (pluginSlackSpy.count, 1)
            // switch back and check that works
            slackModel.plugin = slackPlugin
            compare (pluginSlackSpy.count, 2)
            slackModel.update()
            wait (100)
            compare (countSlackSpy.count, 0)
            wait (200)
            compare (countSlackSpy.count, 1)
        }
        function test_error_geocode() {
            // basic immediate geocode error
            clear_immediate_model()
            immediateModel.query = errorAddress1
            immediateModel.update()
            compare (errorStringImmediateSpy.count, 1)
            compare (immediateModel.errorString, errorAddress1.street)
            compare (immediateModel.error, GeocodeModel.CommunicationError) // county of the address (2)
            compare (immediateModel.count, 0)
            compare (statusImmediateSpy.count, 2)
            compare (immediateModel.status, GeocodeModel.Error)
            // basic delayed geocode error
            clear_slack_model()
            slackModel.query = errorAddress1
            errorAddress1.street = "error code 2"
            slackModel.update()
            compare (errorStringSlackSpy.count, 0)
            compare (errorSlackSpy.count, 0)
            tryCompare (errorStringSlackSpy, "count", 1)
            tryCompare (errorSlackSpy, "count", 1)
            compare (slackModel.errorString, errorAddress1.street)
            compare (slackModel.error, GeocodeModel.CommunicationError)
            compare (slackModel.count, 0)
            // Check that we recover
            slackModel.query = address1
            slackModel.update()
            tryCompare(countSlackSpy, "count", 1)
            compare (slackModel.count, 2)
            compare (errorStringSlackSpy.count, 2)
            compare (errorSlackSpy.count, 2)
            compare (slackModel.errorString, "")
            compare (slackModel.error, GeocodeModel.NoError)
        }

        function test_error_reverse_geocode() {
            // basic immediate geocode error
            clear_immediate_model()
            immediateModel.query = errorCoordinate1
            immediateModel.update()
            if (immediateModel.errorString != "")
                compare (errorStringImmediateSpy.count, 1) // the previous error is cleared upon update()
            else
                compare (errorImmediateSpy.count, 1)
            compare (immediateModel.errorString, "error")
            compare (immediateModel.error, GeocodeModel.ParseError)
            compare (immediateModel.count, 0)
            compare (statusImmediateSpy.count, 2)
            compare (immediateModel.status, GeocodeModel.Error)
            // basic delayed geocode error
            clear_slack_model()
            slackModel.query = errorCoordinate1
            slackModel.update()
            compare (errorStringSlackSpy.count, 0)
            compare (errorSlackSpy.count, 0)
            if (slackModel.errorString != "")
                tryCompare (errorStringSlackSpy, "count", 2)
            else
                tryCompare (errorStringSlackSpy, "count", 1)
            compare (slackModel.errorString, "error")
            compare (slackModel.error, GeocodeModel.ParseError)
            compare (slackModel.count, 0)
            // Check that we recover
            slackModel.query = rcoordinate1
            slackModel.update()
            tryCompare(countSlackSpy, "count", 1)
            compare (slackModel.count, 2)
            compare (errorStringSlackSpy.count, 2)
            compare (errorSlackSpy.count, 2)
            compare (slackModel.errorString, "")
            compare (slackModel.error, GeocodeModel.NoError)
        }
        function test_basic_address_geocode() {
            testQuerySpy.clear()
            locationsSpy.clear()
            testStatusSpy.clear()
            testModel.reset()
            countSpy.clear()
            compare (locationsSpy.count, 0)
            compare (testModel.errorString, "")
            compare (testModel.error, GeocodeModel.NoError)
            compare (testModel.count, 0)
            testModel.query = address1
            compare (testQuerySpy.count, 1)
            testModel.update()
            tryCompare (locationsSpy, "count", 1) // 5 sec
            compare (testModel.errorString, "")
            compare (testModel.error, GeocodeModel.NoError)
            compare (testModel.count, 2)
            compare (testQuerySpy.count, 1)
            compare (testStatusSpy.count, 2)
            compare (testModel.status, GeocodeModel.Ready)
            compare (testModel.get(0).address.street, "wellknown street")
            compare (testModel.get(0).address.city, "expected city")
        }

        function test_basic_freetext_geocode() {
            testQuerySpy.clear()
            locationsSpy.clear()
            testStatusSpy.clear()
            testModel.reset()
            countSpy.clear()
            compare (locationsSpy.count, 0)
            compare (testModel.errorString, "")
            compare (testModel.error, GeocodeModel.NoError)
            compare (testModel.count, 0)
            testModel.limit = 5  // number of places echoed back
            testModel.offset = 10 // 'county' set in the places
            // Test successful case
            testModel.query = "Freetext geocode"
            compare(testQuerySpy.count, 1)
            testModel.update();
            tryCompare (locationsSpy, "count", 1) // 5 sec
            tryCompare(countSpy, "count", 1)
            tryCompare(testModel, "count", 5)
            compare(testModel.get(0).address.county, "10")
            // Test error case
            testModel.query = "2" // tells plugin to echo error '2'
            compare(testQuerySpy.count, 2)
            testModel.update();
            tryCompare (locationsSpy, "count", 2) // 5 sec
            tryCompare(countSpy, "count", 2)
            tryCompare(testModel, "count", 0)
            compare(testModel.errorString, "2")
            compare (testModel.error, GeocodeModel.CommunicationError)
            testModel.reset()
            tryCompare(countSpy, "count", 2)
            compare (testModel.count, 0)
        }

        function test_delayed_freetext_geocode() {
            clear_slack_model()
            slackModel.limit = 5  // number of places echoed back
            slackModel.offset = 10 // 'county' set in the places
            // Basic successful case
            slackModel.query = "freetext geocode"
            compare (querySlackSpy.count, 1)
            slackModel.update()
            wait (100)
            compare (countSlackSpy.count, 0)
            compare (locationsSlackSpy.count, 0)
            compare (slackModel.count, 0)
            wait (200)
            compare (slackModel.count, 5)
            compare (countSlackSpy.count, 1)
            compare (locationsSlackSpy.count, 1)
            // Frequent updates, previous requests are aborted
            slackModel.reset()
            locationsSlackSpy.clear()
            countSlackSpy.clear()
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            wait (200)
            compare (locationsSlackSpy.count, 1)
            compare(countSlackSpy.count, 1)
            compare(slackModel.count, 5) // limit
        }

        function test_geocode_auto_updates() {
            compare (automaticModel.count, 4) // should be something already
            compare (automaticLocationsSpy.count, 1)
            // change query and its contents and verify that autoupdate occurs
            automaticAddress1.county = 6
            wait (300)
            compare (automaticLocationsSpy.count, 2)
            compare (automaticModel.count, 6)
            automaticAddress1.street = "The Avenue"
            wait (300)
            compare (automaticLocationsSpy.count, 3)
            compare (automaticModel.count, 6)
            automaticModel.query = automaticCoordinate1
            wait (300)
            compare (automaticLocationsSpy.count, 4)
            compare (automaticModel.count, 3)
        }

        function test_delayed_geocode() {
            // basic delayed response
            slackModel.reset()
            querySlackSpy.clear()
            countSlackSpy.clear()
            locationsSlackSpy.clear()
            slackModel.query = slackAddress1
            slackAddress1.county = "7"
            compare (querySlackSpy.count, 1)
            slackModel.update()
            wait (100)
            compare (countSlackSpy.count, 0)
            compare (locationsSlackSpy.count, 0)
            compare (slackModel.count, 0)
            wait (200)
            compare (countSlackSpy.count, 1)
            compare (locationsSlackSpy.count, 1)
            compare (slackModel.count, 7) //  slackAddress1.county)
            // Frequent updates, previous requests are aborted
            slackModel.reset()
            locationsSlackSpy.clear()
            countSlackSpy.clear()
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            wait (200)
            compare (locationsSlackSpy.count, 1)
            compare(countSlackSpy.count, 1)
            compare(slackModel.count, 7) // slackAddress1.county
        }
        function test_basic_reverse_geocode() {
            testModel.reset()
            testQuerySpy.clear()
            locationsSpy.clear()
            testStatusSpy.clear()
            countSpy.clear()
            compare (testModel.errorString, "")
            compare (testModel.error, GeocodeModel.NoError)
            compare (testModel.count, 0)
            compare (testQuerySpy.count, 0)
            testModel.query = rcoordinate1
            compare (testQuerySpy.count, 1)
            testModel.update()
            tryCompare (locationsSpy, "count", 1) // 5 sec
            tryCompare(countSpy, "count", 1)
            compare (testModel.errorString, "")
            compare (testModel.error, GeocodeModel.NoError)
            compare (testModel.count, 2)
            testModel.reset()
            tryCompare(countSpy, "count", 2)
            compare (testModel.count, 0)
        }
        function test_delayed_reverse_geocode() {
            clear_slack_model()
            slackModel.query = slackCoordinate1
            compare (querySlackSpy.count, 1)
            slackModel.update()
            wait (100)
            compare (countSlackSpy.count, 0)
            compare (locationsSlackSpy.count, 0)
            compare (slackModel.count, 0)
            wait (200)
            compare (countSlackSpy.count, 1)
            compare (locationsSlackSpy.count, 1)
            compare (slackModel.count, 3) //  slackCoordinate1.longitude
            // Frequent updates, previous requests are aborted
            slackModel.reset()
            locationsSlackSpy.clear()
            countSlackSpy.clear()
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            slackModel.update()
            wait (100)
            compare(locationsSlackSpy.count, 0)
            compare(countSlackSpy.count, 0)
            wait (200)
            compare (locationsSlackSpy.count, 1)
            compare(countSlackSpy.count, 1)
            compare(slackModel.count, 3) // slackCoordinate1.longitude
        }
    }
}
